/*
 * Copyright (C) 2022-2024 Huawei Device Co., Ltd.
 * Licensed under the MIT License, (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://opensource.org/licenses/MIT
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import type { PubSubSupport } from '../interface/PubSubSupport'
import { SubscriptionManager } from '../subscription/SubscriptionManager'
import { BusRuntime } from './BusRuntime'
import type { IMessagePublication } from './IMessagePublication'
import type { IBusConfiguration } from '../config/IBusConfiguration'
import { SyncPubSub } from '../config/SyncPubSub'
import { MessagePublicationFactory } from './MessagePublication'
import { Subscription } from '../subscription/Subscription'
import ArrayList from '@ohos.util.ArrayList';
import { LogUtil } from '../../../../utils/LogUtil'


export abstract class AbstractPubSubSupport<T> implements PubSubSupport<T> {
  private subscriptionManager: SubscriptionManager;
  private runtime: BusRuntime;
  private publicationFactory: MessagePublicationFactory;

  constructor(config: IBusConfiguration) {
    LogUtil.info('Initializing AbstractPubSubSupport');
    this.runtime = new BusRuntime(this);
    let pubSubFeature = config.getFeature('SyncPubSub');
    if (!pubSubFeature) {
      throw new Error('missing Feature');
    }

    let syncFeature = pubSubFeature as SyncPubSub;
    this.subscriptionManager = syncFeature.getSubscriptionManagerProvider()
      .createManager(
        syncFeature.getMetadataReader(),
        syncFeature.getSubscriptionFactory(),
        this.runtime
      );
    this.publicationFactory = syncFeature.getPublicationFactory();
  }

  subscribe(listener: Object): void {
    LogUtil.debug(`Subscribing listener`);
    if (this.subscriptionManager) {
      this.subscriptionManager.subscribe(listener);
    }
  }

  unSubscribe(listener: Object): boolean {
    LogUtil.debug(`Unsubscribing listener`);
    if (this.subscriptionManager) {
      return this.subscriptionManager.unsubscribe(listener);
    }
    return false;
  }

  getSubscriptionManager(): SubscriptionManager {
    LogUtil.debug('Accessing subscription manager');
    return this.subscriptionManager;
  }

  publish(message: T) {
    // TODO
  }

  getRunTime(): BusRuntime {
    LogUtil.debug('Accessing bus runtime');
    return this.runtime;
  }

  publishAsyncStart(message: T, pub: IMessagePublication) {
    new Promise<string>((resolve, reject) => {
      try {
        pub.executeAsyn();
        resolve('success');
      } catch (error) {
        reject(error);
      }
    }).then((v) => {
      LogUtil.log(v.toString())
    }).catch((err) => {
      LogUtil.error(err);
    })
  }

  createMessagePublication(message: T): IMessagePublication {
    let subManager: SubscriptionManager = this.getSubscriptionManager();
    let array: Array<Subscription> = subManager.getSubscriptionsByClassName();
    if (!array) {
      throw new Error('no found Subscription of class name');
    }
    let arrayListSun = new ArrayList<Subscription>();
    array.forEach((value, index) => {
      arrayListSun.add(value);
    })
    try {
      arrayListSun.sort((first: Subscription, second: Subscription) => second.getPriority() - first.getPriority());
    } catch (e) {
      LogUtil.error(e);
    }
    var messagePublication = this.publicationFactory.createPublication(this.runtime, arrayListSun, message);
    return messagePublication;
  }
}